Skip to content

fix: allow shallow routing during initial render#16338

Closed
Nic-Polumeyv wants to merge 1 commit into
sveltejs:version-3from
Nic-Polumeyv:fix-shallow-routing-initial-effect
Closed

fix: allow shallow routing during initial render#16338
Nic-Polumeyv wants to merge 1 commit into
sveltejs:version-3from
Nic-Polumeyv:fix-shallow-routing-initial-effect

Conversation

@Nic-Polumeyv

@Nic-Polumeyv Nic-Polumeyv commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

closes #15927

Calling replaceState or pushState inside a top-level $effect throws Cannot call replaceState(...) before router is initialized in dev, even though everything shallow routing needs already exists at that point.

Twas the release before Svelte 5, and onMount still ran before the router existed, so calling these functions there crashed on root.$set (#11466). #11968 wrapped that crash in a readable dev error, on the reasoning that Svelte 5 had made the problem unreachable since onMount now runs after initial render. That was right about onMount and wrong about $effect, which flushes while the root component is still being created. Everything shallow routing needs already exists in that window, page and the history indexes. So the dev error no longer means what it says.

Two changes.

  • the dev guard now checks a router_initialized flag that flips right before the root component is created, once everything shallow routing needs is in place. Genuinely-too-early calls, from module scope or load, throw the same error as before.
  • writing the back-navigation test surfaced a second bug that also breaks production. The page.url.href read inside both functions is tracked, so any effect calling them silently depends on page.url, and going back to a pushed entry re-ran the effect, which re-pushed the state it had just left. fix: prevent infinite loop when calling pushState/replaceState in effect #13914 fixed this class for clone_page, this read escaped it. It's untracked now.

started is untouched, it also gates initial fetch handling, navigating and scroll behavior.

An earlier revision targeted main, where the stakes are higher: kit 2's pushState/replaceState still call root.$set for the legacy stores, so the same call crashes production with TypeError: Cannot read properties of undefined (reading '$set'). That part of the fix (falling back to the store while root doesn't exist yet) has no equivalent here since the stores are gone (#15499). If a 2.x patch is wanted I can reopen that version against main.

The new tests fail on version-3 without the fix. In dev both hit the guard, in build the pushState test catches the effect re-run.

Overlaps with #16307 on the PAGE_URL_KEY lines. Whichever merges second, keep resolve_url(url).href and drop the untrack, since resolve_url never had the reactive dependency.


Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

Edits

  • Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed.

@pkg-svelte-dev

pkg-svelte-dev Bot commented Jul 14, 2026

Copy link
Copy Markdown

Install the latest version of @sveltejs/kit from 3718f4a:

pnpm add https://pkg.svelte.dev/@sveltejs/kit/c/3718f4a45d15de3a62aac5f4ed742a0deb17d36e

Open in pkg.svelte.dev: https://pkg.svelte.dev/repos/kit/pr/16338

Note

This PR is from a fork. A maintainer must approve approve each commit before it can be built and installed.

@changeset-bot

changeset-bot Bot commented Jul 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3718f4a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sveltejs/kit Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Comment thread packages/kit/src/runtime/client/client.js Outdated
@Nic-Polumeyv

Copy link
Copy Markdown
Contributor Author

This overlaps with #16307 on the PAGE_URL_KEY lines. Whichever merges second, keep resolve_url(url).href and drop the untrack, since resolve_url only reads document.baseURI and never had the reactive dependency.

@Nic-Polumeyv
Nic-Polumeyv changed the base branch from main to version-3 July 15, 2026 01:07
@Nic-Polumeyv
Nic-Polumeyv force-pushed the fix-shallow-routing-initial-effect branch from 3a2bec5 to 4f79e29 Compare July 15, 2026 01:07
@Nic-Polumeyv
Nic-Polumeyv force-pushed the fix-shallow-routing-initial-effect branch from 4f79e29 to 3718f4a Compare July 15, 2026 01:59
@Nic-Polumeyv

Copy link
Copy Markdown
Contributor Author

#16389 rewrites both of these functions and covers the untrack half of this diff, so closing. The #15927 initial-render question is worth revisiting against the new implementation once it lands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Cannot call replaceState(...) before router is initialized" in $effect

1 participant